package nimy.info.android.dinnertime.page;

import java.io.InputStreamReader;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import nimy.info.android.dinnertime.Constants;
import nimy.info.android.dinnertime.HomeActivity;
import nimy.info.android.dinnertime.R;
import nimy.info.android.dinnertime.adapter.RecipeKeywordItemAdapter;
import nimy.info.android.dinnertime.connectivity.LoaderState;
import nimy.info.android.dinnertime.connectivity.ResponseObject;
import nimy.info.android.dinnertime.connectivity.ResponseParser;
import nimy.info.android.dinnertime.connectivity.WebConnector;
import nimy.info.android.dinnertime.exception.ApplicationException;
import nimy.info.android.dinnertime.model.RecipeKeyword;
import nimy.info.android.dinnertime.utils.Utils;

import org.apache.http.HttpStatus;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;

import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import com.actionbarsherlock.view.MenuItem.OnMenuItemClickListener;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.internal.StringMap;
import com.google.gson.stream.JsonReader;

/**
 * 
 * @author 234aini@gmail.com 2012-10-14
 * 
 */
public class RecipeKeywordPage extends AbstractSinglePage implements
		LoaderCallbacks<LoaderState<List<RecipeKeyword>>> {

	private static final String TAG = RecipeKeywordPage.class.getName();
	private static final String EXIST_POPULAR_KEYWORDS_KEY = "EXIST_POPULAR_KEYWORDS";
	private ListView mListView;
	private View mSearchGroupView;
	private View mView;
	private RecipeKeywordItemAdapter mListAdapter;

	private List<RecipeKeyword> mPopularKeywords;
	private RecipeKeywordLoader mLoader;

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		getLoaderManager().initLoader(Constants.LOADER_RECIPE_KEYWORDS,
				savedInstanceState, this);
		// We have a menu item to show in action bar.
		setHasOptionsMenu(true);
		super.onActivityCreated(savedInstanceState);
	}

	@Override
	public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
		// Place an action bar item for searching.
		MenuItem item = menu.add("Refresh");
		item.setIcon(android.R.drawable.ic_popup_sync);
		item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
		item.setOnMenuItemClickListener(new OnMenuItemClickListener() {
			@Override
			public boolean onMenuItemClick(MenuItem item) {
				if (mLoader != null && !mLoader.isAbandoned()) {
					mLoader.startLoading();
				}
				return true;
			}
		});
		inflaterShareAction(menu, inflater);
	}

	@SuppressWarnings("unchecked")
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		View inflated = inflater.inflate(R.layout.page_recipe_keyword,
				container, false);
		mView = inflated.findViewById(R.id.fragment_recipe_keyword);
		mSearchGroupView = mView.findViewById(R.id.searchInputGroup);
		mListView = (ListView) mView.findViewById(R.id.view_recipe_keywords);
		setupRecipeSearchTextControls(mSearchGroupView);
		setupRecipeKeywordListView(mListView);

		if (savedInstanceState != null) {
			mPopularKeywords = (List<RecipeKeyword>) savedInstanceState
					.getSerializable(EXIST_POPULAR_KEYWORDS_KEY);
		}
		return inflated;
	}

	@Override
	public void onSaveInstanceState(Bundle outState) {
		if (mPopularKeywords != null) {
			outState.putSerializable(EXIST_POPULAR_KEYWORDS_KEY,
					(Serializable) mPopularKeywords);
		}
		super.onSaveInstanceState(outState);
	}

	private void setupRecipeKeywordListView(ListView mKeywordListView2) {
		mListView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> adapterView, View itemView,
					int position, long itemId) {
				RecipeKeyword itemAtPosition = (RecipeKeyword) mListView
						.getItemAtPosition(position);
				if (itemAtPosition != null) {
					HomeActivity.getApplicaiton().setCurrentRecipeKeyword(
							itemAtPosition.getName());
					HomeActivity.getApplicaiton().searchRecipes(
							itemAtPosition.getName());
				}
			}
		});

		mListAdapter = new RecipeKeywordItemAdapter(getActivity()
				.getApplicationContext());
		mListView.setAdapter(mListAdapter);
	}

	/**
	 * Setup the edit text settings
	 * 
	 * @param recipePageView
	 */
	private void setupRecipeSearchTextControls(View recipePageView) {
		final EditText editTextSearch = (EditText) recipePageView
				.findViewById(R.id.txt_search);
		ImageButton searchButton = (ImageButton) recipePageView
				.findViewById(R.id.searchImageButton);
		searchButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				queryRecipeFromInput(editTextSearch);
			}
		});
		editTextSearch.setOnEditorActionListener(new OnEditorActionListener() {

			@Override
			public boolean onEditorAction(TextView v, int actionId,
					KeyEvent event) {
				queryRecipeFromInput(editTextSearch);
				return false;
			}
		});
	}

	protected void queryRecipeFromInput(EditText editTextSearch) {

		String searchInputName = (String) editTextSearch.getText().toString()
				.trim();
		if (searchInputName != null && !searchInputName.trim().equals("")) {
			InputMethodManager imm = (InputMethodManager) getContext()
					.getSystemService(Context.INPUT_METHOD_SERVICE);
			boolean isOpen = imm.isActive();
			if (isOpen) {
				imm.hideSoftInputFromWindow(getContext().getCurrentFocus()
						.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);

			}
			editTextSearch.clearFocus();
			HomeActivity.getApplicaiton().searchRecipes(searchInputName);
		} else {
			Utils.toastAtCenter(getContext(), getContext().getResources()
					.getString(R.string.recipe_search_no_input),
					Toast.LENGTH_LONG);
		}

	}

	public HomeActivity getContext() {
		return (HomeActivity) getActivity();
	}

	@Override
	public Loader<LoaderState<List<RecipeKeyword>>> onCreateLoader(
			int loaderId, Bundle bundle) {
		mLoader = new RecipeKeywordLoader(getSherlockActivity(), bundle,
				mPopularKeywords);
		return mLoader;
	}

	@Override
	public void onLoadFinished(Loader<LoaderState<List<RecipeKeyword>>> loader,
			LoaderState<List<RecipeKeyword>> result) {
		if (result != null && result.getData() != null) {
			this.mPopularKeywords = result.getData(); // keep status
			mListAdapter.setModel(result.getData(), false);
			HomeActivity.getApplicaiton().endSplash(); // remove the splash
		} else {
			if (result.getThrowable() != null && !loader.isAbandoned()) {
				HomeActivity.getApplicaiton().showErrorMessage(
						R.string.error_network_timeout_exception);
			}
		}
	}

	@Override
	public void onLoaderReset(Loader<LoaderState<List<RecipeKeyword>>> loader) {
		loader.stopLoading();
	}

	/**
	 * Help to load the popular recipe keywords
	 * 
	 * @author 234aini@gmail.com 2012-10-20
	 * 
	 */
	public static class RecipeKeywordLoader extends
			AsyncTaskLoader<LoaderState<List<RecipeKeyword>>> {
		private static final String TAG = RecipeKeywordLoader.class.getName();
		private List<RecipeKeyword> mLoaderPopularKeywords;

		public RecipeKeywordLoader(Context context, Bundle bundle,
				List<RecipeKeyword> mPopularKeywords) {
			super(context);
			this.mLoaderPopularKeywords = mPopularKeywords;
		}

		@Override
		public LoaderState<List<RecipeKeyword>> loadInBackground() {
			String url = Utils.getProperty(Constants.CONFIG.TAG.key(), "");
			try {
				WebConnector<List<RecipeKeyword>> connector = WebConnector
						.getConnector(getContext(), url,
								new ResponseParser<List<RecipeKeyword>>() {
									@Override
									public List<RecipeKeyword> parse(
											ResponseObject response)
											throws ApplicationException {
										if (response.getStatusCode() == HttpStatus.SC_OK) {
											GsonBuilder gsonb = new GsonBuilder();
											Gson gson = gsonb.create();
											JsonReader jsonReader = new JsonReader(
													new InputStreamReader(
															response.getInputStream()));
											List<StringMap<Object>> fromJson = gson
													.fromJson(jsonReader,
															List.class);
											List<RecipeKeyword> list = new ArrayList<RecipeKeyword>(
													fromJson.size());
											for (StringMap<Object> o : fromJson) {
												Double count = (Double) o
														.get("count");
												RecipeKeyword keyword = new RecipeKeyword(
														(String) o.get("tag"),
														count == null ? 0
																: count.intValue());
												list.add(keyword);
											}
											return list;
										} else {
											throw new ApplicationException(
													"Parse response object failed. "
															+ response);
										}
									}
								});
				List<RecipeKeyword> parseResponseTo = connector
						.parseResponseTo();
				return new LoaderState<List<RecipeKeyword>>(parseResponseTo);
			} catch (Exception e) {
				Log.e(TAG,
						"Failed to fetch data from:" + url + " - "
								+ e.getMessage(), e);
				return new LoaderState<List<RecipeKeyword>>(e);
			}
		}

		/**
		 * Handles a request to start the Loader.
		 */
		@Override
		protected void onStartLoading() {
			Log.d(TAG, "Start loading the popular keywords");
			if (mLoaderPopularKeywords != null) {
				// If we currently have a result available, deliver it
				// immediately.
				deliverResult(new LoaderState<List<RecipeKeyword>>(
						mLoaderPopularKeywords));
			}

			// Has something interesting in the configuration changed since we
			// last built the app list?

			if (takeContentChanged() || mLoaderPopularKeywords == null
					|| mLoaderPopularKeywords.isEmpty()) {
				// If the data has changed since the last time it was loaded
				// or is not currently available, start a load.
				forceLoad();
			}
		}

		/**
		 * Called when there is new data to deliver to the client. The super
		 * class will take care of delivering it; the implementation here just
		 * adds a little more logic.
		 */
		@Override
		public void deliverResult(LoaderState<List<RecipeKeyword>> loaderResult) {
			if (isReset()) {
				// An async query came in while the loader is stopped. We
				// don't need the result.
				if (loaderResult != null && loaderResult.getData() != null) {
					onReleaseResources(loaderResult.getData());
				}
			}
			List<RecipeKeyword> oldApps = loaderResult.getData();
			mLoaderPopularKeywords = loaderResult.getData();
			if (isStarted()) {
				// If the Loader is currently started, we can immediately
				// deliver its results.
				super.deliverResult(loaderResult);
			}

			// At this point we can release the resources associated with
			// 'oldApps' if needed; now that the new result is delivered we
			// know that it is no longer in use.
			if (oldApps != null) {
				onReleaseResources(oldApps);
			}
			HomeActivity.getApplicaiton().endSplash();
		}

		/**
		 * Handles a request to stop the Loader.
		 */
		@Override
		protected void onStopLoading() {
			// Attempt to cancel the current load task if possible.
			cancelLoad();
		}

		/**
		 * Handles a request to cancel a load.
		 */
		@Override
		public void onCanceled(LoaderState<List<RecipeKeyword>> loadResult) {
			super.onCanceled(loadResult);

			// At this point we can release the resources associated with 'apps'
			// if needed.
			onReleaseResources(loadResult.getData());
		}

		/**
		 * Handles a request to completely reset the Loader.
		 */
		@Override
		protected void onReset() {
			super.onReset();

			// Ensure the loader is stopped
			onStopLoading();

			// At this point we can release the resources associated with 'apps'
			// if needed.
			if (mLoaderPopularKeywords != null) {
				onReleaseResources(mLoaderPopularKeywords);
				mLoaderPopularKeywords = null;
			}
		}

		protected void onReleaseResources(List<RecipeKeyword> keywords) {
			// TODO
		}
	}

	@Override
	public void onPause() {
		if (mPopularKeywords != null && !mPopularKeywords.isEmpty()) {
			// RecipeKeywordLoader loader = getLoaderManager().getLoader(
			// Constants.LOADER_RECIPE_KEYWORDS);
			// loader.setLoaderPopularKeywords(mPopularKeywords);
			// loader.startLoading();
		}
		Log.i(TAG, "Fragment s pause");
		super.onPause();
	}

	@Override
	public void onStop() {
		Log.i(TAG, "Fragment s stop");
		super.onStop();
	}

	@Override
	public void onResume() {
		Log.i(TAG, "Fragment s Resume");
		super.onResume();
	}

	@Override
	public void onStart() {
		Log.i(TAG, "Fragment s Start");
		super.onStart();
	}

	// functions to help save status when pause or stop activity

	protected static interface OnRecipeKeywordListener {
		public void onChanged(RecipeKeyword newKeyword, RecipeKeyword oldKeyword);
	}
}
